#include "songmodel.h"
#include <QCryptographicHash>
#include <QJsonDocument>
#include <QJsonObject>
#include <config.h>
#include <QSqlQuery>
#include "log/EZQLOG.h"
#include <QString>
#include <QJsonObject>
#include <QJsonValue>

using namespace EZTally;

SongModel::SongModel()
    :QObject(0)
{
    _dbid = 0;
    connect(&_netManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(onGetSongUrl(QNetworkReply*)));
}
int SongModel::dbid() const
{
    return _dbid;
}

void SongModel::setDbid(int dbid)
{
    _dbid = dbid;
}


SongModel::~SongModel()
{
    disconnect(this);
}


int SongModel::sid() const
{
    return _sid;
}

void SongModel::setSid(int sid)
{
    _sid = sid;
}

double SongModel::time() const
{
    return _time;
}

void SongModel::setTime(double time)
{
    _time = time;
}

QString SongModel::title() const
{
    return _title;
}

void SongModel::setTitle(const QString &title)
{
    _title = title;
}

QStringList SongModel::qualityKeys()
{
    QStringList keys = _qualityMap.keys();
    return keys;
}

void SongModel::setQualityWithKey(QString &key, SongModel::Quality &quality)
{
    _qualityMap[key] = quality;
}
SongModel::Quality SongModel::qualityWithKey(QString &key)
{
    if(_qualityMap.find(key)!=_qualityMap.end())
    {
        return _qualityMap[key];
    }else{
        Quality quality;
        return quality;
    }
}

QString SongModel::getUrlWith(const QString &key,int *getType)
{

    if(_qualityMap.find(key)==_qualityMap.end()){
        if(getType){
            *getType = -1;
        }
        return QString("");
    }

    SongModel::Quality quality = _qualityMap[key];

    if(quality.url.isEmpty()==false){
        if(getType){
            *getType = 1;
        }
        return quality.url;
    }

    if(quality.hash.isEmpty()){
        if(getType){
            *getType = -2;
        }
        return QString("");
    }

    if(_requestKeys.find(key)!=_requestKeys.end()){
        if(getType){
            *getType = 0;
        }
        return QString("");
    }

//    cmd=3 流畅 cmd=4 较高品质
    QString urlStr("http://trackercdn.kugou.com/i/?cmd=%1&pid=3&authType=1&hash=%2&key=%3&uid=");
    QString hashKey(quality.hash +"kgcloud");
    QByteArray md5Bytes = QCryptographicHash::hash(hashKey.toStdString().c_str(),QCryptographicHash::Md5);
    QString md5Key(md5Bytes.toHex().toUpper());
    urlStr = urlStr.arg(4).arg(quality.hash).arg(md5Key);

    QUrl url(urlStr);
    QNetworkRequest request(url);
//    QNetworkReply r
    _requestKeys[key] = request;
    _netManager.get(request);

    if(getType){
        *getType = 0;
    }
    return QString("");
}

void SongModel::onGetSongUrl(QNetworkReply *reply)
{
    QNetworkRequest request = reply->request();
    QString key = _requestKeys.key(request);
    Quality quality = _qualityMap[key];

//    QString str(reply->readAll());
//    qDebug() << str;
//"{"status":1,"url":"http:\/\/storage3.ios.kugou.com\/M01\/01\/15\/e4Olpk5qUqW3rg98AJC26rv2XyI715.mp3",
//    "fileSize":9484010,"timeLength":237,"bitRate":320000,"q":20801,"fileHead":3,"extName":"mp3",
//    "fileName":"\u9648\u6167\u5a34 - \u98d8\u96ea"}"
    QByteArray bytes = reply->readAll();
    QJsonDocument document = QJsonDocument::fromJson(bytes,0);
    int error = 0;
    if(document.isObject()){
        QJsonObject rootObj = document.object();
        int status = rootObj["status"].toInt();
        if(status==1){
            quality.url = rootObj["url"].toString();
            quality.size = rootObj["fileSize"].toInt();
            quality.timeLength = rootObj["timeLength"].toDouble();
            quality.extName = rootObj["extName"].toString();
            _qualityMap[key] = quality;
        }else{
            error = -2;
        }
    }else{
        error = -1;
    }
    emit sigSongUrlChange(key,error);

    _requestKeys.remove(key);
}
void SongModel::initSongWith(QSqlQuery &query)
{
    _dbid = query.value("id").toInt();
    _sid = query.value("sid").toInt();
    _title = query.value("title").toString();
    _time = query.value("time").toDouble();
    QString qualitys = query.value("qualitys").toString();
    QByteArray bytes;
    bytes.append(qualitys);
    QJsonDocument document = QJsonDocument::fromJson(bytes);
    QJsonObject obj = document.object();
    QJsonObject::iterator iter = obj.begin();
    while (iter!=obj.end()) {
        QString key = iter.key();
        QJsonValue value = (*iter);
        SongModel::Quality quality;
        QJsonObject qobj = value.toObject();
        quality.initWithJson(qobj);
        setQualityWithKey(key,quality);
        iter++;
    }
}

void SongModel::saveToDB(bool isReplace)
{
    SongModel::checkDBState();

    QSqlDatabase db = Config::defaultConfig()->dataBase();
    if(_dbid<=0){
        QString findsql("select id from %1 where title = ?;");
        findsql = findsql.arg(SongModel_DB_TABLE);
        QSqlQuery findquery(db);
        findquery.prepare(findsql);
        findquery.bindValue(0,_title);
        bool  code = findquery.exec();
        int fid = 0;
        if(code && findquery.next()){
            fid = findquery.value(0).toInt();
            if(_dbid<=0){
                _dbid = fid;
            }
        }
    }
    if(isReplace==false && _dbid>0){
        return;
    }


    QString sql("insert or replace into %1 values(:id,:sid,:title,:time,:qualitys);");
    sql = sql.arg(SongModel_DB_TABLE);
    QSqlQuery query(db);
    query.prepare(sql);
    if(_dbid>0){
        query.bindValue(":id",_dbid);
    }

    QString qualitys = qualityToString();

    query.bindValue(":sid",_sid);
    query.bindValue(":title",_title);
    query.bindValue(":time",_time);
    query.bindValue(":qualitys",qualitys);
    bool isSave = query.exec();
    if(isSave && _dbid<=0){
        QString nidSql("select last_insert_rowid() id");
//        nidSql.arg(MyPlayListModel_DB_TABLE);
        QSqlQuery idquery(db);
        idquery.exec(nidSql);
        if(idquery.next()){
            _dbid = idquery.value(0).toInt();
        }
    }
    if(isSave==false){
        EZDebug << "save error song:" << _dbid << ":" << _title ;
    }

}
QString SongModel::qualityToString()
{
    QMap<QString,SongModel::Quality>::iterator iter = _qualityMap.begin();
//    QString strs;
    QJsonObject obj;
    while(iter!=_qualityMap.end()){
        QString key = iter.key();
        SongModel::Quality quality = (*iter);

        QJsonObject qualityJsonObj;
        if(QString::compare(key,songHash_localPath)==0){
            qualityJsonObj = quality.tojson(true);
        }else{
            qualityJsonObj = quality.tojson(false);
        }

        QJsonValue jvalue(qualityJsonObj);
        obj[key] = jvalue;
        iter++;
    }

    QJsonDocument document;
    document.setObject(obj);
    QByteArray bytes = document.toJson(QJsonDocument::Compact);
    QString strs(bytes);
    EZDebug << "qualityToString:" << strs;
    return strs;
}

void SongModel::checkDBState()
{
    static bool isCheck = false;
    if(isCheck){
        return ;
    }

    { // create database
        QString sql(QString("create table ")+SongModel_DB_TABLE+"("
                    "id integer primary key autoincrement,"
                    "sid integer,"
                    "title TEXT,"
                    "time REAL,"
                    "qualitys TEXT"
                    ")");

        QSqlDatabase db = Config::defaultConfig()->dataBase();
        QSqlQuery query(db);
        bool isCreate = query.exec(sql);
        EZDebug << "init " << SongModel_DB_TABLE << isCreate;
    }


    isCheck = true;
}

QJsonObject SongModel::Quality::tojson(bool keepUrl)
{
    QJsonObject obj;
    QJsonValue hashValue(this->hash);
    QJsonValue urlValue(this->url);
    QJsonValue sizeValue(this->size);
    QJsonValue timeLengthValue(this->timeLength);
    QJsonValue extNameValue(this->extName);

    obj["hash"] = hashValue;
    if(keepUrl){
        obj["url"] = urlValue;
    }
    obj["size"] = sizeValue;
    obj["timeLength"] = timeLengthValue;
    obj["extName"] = extNameValue;

    return obj;
//    QJsonDocument document;
//    document.setObject(obj);
//    QByteArray bytes = document.toJson(QJsonDocument::Indented);
//    return bytes;
}

int SongModel::Quality::initWithJson(QJsonObject &obj)
{
//    QJsonParseError err;
//    QJsonDocument document = QJsonDocument::fromJson(bytearray,&err);
//    if(err != QJsonParseError::NoError){
//        return -1;
//    }
//    QJsonObject obj = document.object();
    this->hash = obj["hash"].toString();
    this->url = obj["url"].toString();
    this->size = obj["size"].toInt();
    this->timeLength = obj["timeLength"].toDouble();
    this->extName = obj["extName"].toString();
    return 0;
}
